Введение
Введение
MyBlog – это легковесное асинхронное веб-приложение для ведения личного блога и галереи нейросетевых артов. Построено на базе фреймворка FastAPI. Основная идея проекта – полная автономность. Отсутствие тяжёлых внешних зависимостей (баз данных) и работа через высокоскоростное In-memory кэширование файловой системы. Это сочетает надёжность хранения в плоских файлах (Markdown) с мгновенным откликом интерфейса Это делает проект идеальным для self-hosted развёртывания.
1. Архитектура и серверная логика: main.py
1.1 Инфраструктурные решения
Проект спроектирован с учётом работы за Reverse Proxy (Nginx/Traefik), что делает его максимально гибким для различных сценариев хостинга.
- Middleware для подпапок:
@app.middleware("http")
async def add_proxy_headers(request: Request, call_next):
path_prefix = request.headers.get("X-Forwarded-Prefix")
if path_prefix:
request.scope["root_path"] = path_prefix
return await call_next(request)
- Это критически важный узел. Если сайт крутится не в корне домена, заголовки
X-Forwarded-Prefixпозволяют FastAPI корректно генерировать внутренние ссылки. Без этой прослойки статика и переходы были бы полностью разрушены. - Система реактивного кэширования (In-memory Cache) Для достижения экстремальной производительности при любом количестве статей внедрена система кэширования в оперативной памяти. Сервер индексирует директорию
/postsтолько в три момента: при запуске (событиеstartup), при загрузке новой статьи и при удалении. Во всех остальных случаях список статей отдаётся из памяти мгновенно, минуя обращения к жёсткому диску. Это снижает нагрузку на I/O и делает главную страницу неуязвимой для тормозов даже при наличии тысяч файлов. - Автономная загрузка окружения: Реализована функция
load_env_file, выполняющая парсинг.envбез сторонних библиотек. Поддержка UTF-8 гарантирует безошибочную работу кириллических паролей. - Zero-Dependency Env Parser: Реализован собственный алгоритм парсинга конфигурации, что исключает необходимость в сторонних библиотеках и повышает общую безопасность приложения за счёт минимизации цепочки зависимостей
- Поддержка служебных префиксов: Логика парсинга имён файлов учитывает дескрипторы:
!для закрепления и[]для категорий. - Выбор XHR для загрузки файлов: Использование
xhr.upload.onprogressпозволило реализовать «честный» прогресс-бар для больших медиафайлов. - Динамическое управление путями: Реализована система рекурсивного сканирования. Фронтенд позволяет выбрать подпапку или создать новую «на лету». Визуальное превью пути через
oninputисключает ошибки линковки. - Изолированное удаление (Safe Rmtree): Реализован эндпоинт
/delete_folder. Для предотвращения критических ошибок введена система Forbidden Folders (запрет на удаление корня и системных папок). - Рекурсивная индексация хранилища: Алгоритм
STATIC_DIR.rglob("*")позволяет серверу «видеть» всю глубину вложенности папок в реальном времени, превращаяstaticв структурированное облако контента. - Двухуровневая система блюра: Серверная логика распознаёт суффикс
_Sв именах файлов (например,image_S.jpg). Это служит «железным» маркером для автоматического наложения блюра в Галерее, гарантируя безопасность контента без ручной правки кода.
- Оптимизация длительных сессий (Timeout Handling): Для поддержки загрузки сверхтяжёлых медиафайлов (видео, архивы) в конфигурацию ASGI-сервера внедрён параметр--timeout-keep-alive 600. Это предотвращает разрыв соединения со стороны сервера при длительной передаче данных, что в сочетании с XHR-прогресс-баром обеспечивает надёжный user-experience при работе с файлами объёмом более 1 ГБ.
1.2 Работа с базой данных (Flat-file DB)
Архитектура проекта исключает SQL. Мы используем Flat-file approach:
- Статьи:
.mdфайлы в/posts. - Метаданные галереи:
prompts.json. - Медиа:
static/gallery. - Atomic Folder Deletion: Эндпоинт удаления папок использует
shutil.rmtree, но защищён механизмом «мягкой блокировки» для системных путей. - Гибридная логика доступа: Физическое хранение в плоских файлах сочетается с высокоскоростным индексированием в оперативную память. Это даёт надёжность хранения данных и скорость выдачи контента уровня Redis без установки дополнительных баз данных.
Плюсы: Бэкап блога – это просто копирование папки. Нет оверхеда на коннекты к БД. Скорость доступа к списку постов больше не ограничена скоростью дисковой подсистемы.
Минусы: Отсутствие транзакционности, что полностью нивелируется использованием кэша и атомарных операций записи для персонального блога.
1.3 Система авторизации
Реализована через SessionMiddleware на базе зашифрованных Cookies. Функция require_auth выступает барьером для всех деструктивных действий.
1.3.1 Механизм приватных статей (Access Codes)
Внедрена система дискретных кодов доступа для статей с префиксом [P].
- Жизненный цикл кодов: Прямо из интерфейса автор может выполнить ротацию ключа (Rotate Key) – генерацию нового пароля с перезаписью в
.env. Алгоритм Cleanup Keys очищает конфиг от устаревших записей удалённых постов. - Интеллектуальный шлюз (Smart Access): Система авторизации автоматически распознаёт контекст запроса. Если пользователь переходит по прямой ссылке на приватную статью (префикс
[P]), форма входа динамически трансформируется: поле «Логин» скрывается, а интерфейс предлагает только «Введите код доступа». Это реализовано через проверкуnext_urlв шаблоне Jinja2, что обеспечивает бесшовный UX – гостю не нужно знать системный логинguest, достаточно иметь секретный шестизначный код.
1.4 Контент-пайплайн (Markdown)
Сервер использует динамический рендеринг. Проект поддерживает расширенный синтаксис Obsidian:
- Callouts: Стилизованные блоки
[!INFO],[!WARNING]. - Маркерное выделение: Поддержка
==текст==. - Интерактивные чек-листы: Рендеринг
[x].
1.5 Автоматизация путей через Post-processing
html = html.replace('/blog/static/', '/blog/static/')
Механизм автоматически заменяет относительные пути на абсолютные перед отдачей страницы пользователю. Это гарантирует, что медиаконтент будет корректно отображаться вне зависимости от вложенности URL статьи, а запросы к статике будут мгновенно обрабатываться через Nginx (блок /blog/static/), минуя Python-логику. Это обеспечивает «железную» стабильность отображения картинок и видео.
- UI/UX контроль: Интеллектуальный Path-Preview транслирует имя папки в путь
/static/.... Система дополнена Live-List: при выборе папки мгновенно разворачивается список её файлов. - Техническая безопасность: Поддержка вложенных структур реализована через разрешение символа слеша
\/. Система фильтрации гарантирует защиту от атак Path Traversal.
2. Функциональные блоки (Эндпоинты)
2.1 Галерея и Промты
Галерея – это не просто список картинок. Сервер связывает файлы изображений с их текстовыми описаниями (промтами):
GET /gallery: Сканирует директорию, сортирует файлы по времени изменения (st_mtime) и сопоставляет с данными из JSON.POST /gallery/prompt_save: Обновляет описания. Поддерживается только админом.
2.2 Универсальный медиа-хаб и безопасность загрузки
- Интегрированный менеджер файлов (File Explorer): Внедрён асинхронный поиск через эндпоинт
/list_files/{folder_name:path}. Использование типизации:pathв маршруте позволяет работать со сложными путями. - Безопасность имён (Sanitization): Регулярное выражение
re.sub(r'[^\w\s\-\.\[\]\(\),!«»"\'\u00A0—;?]', ...)очищает имена файлов, сохраняя типографику (ёлочки, тире) и управляющие символы. - Валидация типов: Проверка на уровне
content_typeи «белого списка» расширений (WebP, SVG и др.) гарантирует безопасность хранилища. - Контекстный UI: Интерактивные метки (Folder Tags) и скрытые кнопки удаления папок (эффект
:hover) сохраняют чистоту интерфейса. - Кастомная навигация: Авторская стилизация скроллбара в акцентных цветах в тёмной теме.
- Иерархическая навигация (Smart Folder Tags): Реализована логика динамического «раскрытия» дерева директорий. Чтобы избежать визуального загромождения интерфейса (эффект «каши»), система принудительно скрывает вложенные пути. Метки подпапок (например,
pictures/kartozz) становятся видимыми только при активации родительского раздела (pictures). Это обеспечивает фокус на текущем контексте работы и делает навигацию интуитивно понятной даже при экстремально глубокой вложенности архива. - Визуальный отклик (Active States): Метки папок получили динамическую подсветку (
.active), что в сочетании с живым превью пути (previewPath) исключает ошибки при загрузке контента. При клике на метку происходит не только смена целевой папки, но и мгновенная перефильтрация видимых тегов на стороне клиента. - Опция «Блюр при загрузке»: В интерфейс загрузчика интегрирован чекбокс, который при активации автоматически переименовывает файл на стороне сервера, добавляя суффикс
_S. Серверная логика и шаблоны автоматически распознают этот маркер, применяя к медиафайлу эффект блюра и плашку NSFW, создавая безопасную среду для просмотра контента. - Мультимедийная экспансия: Обновлённый список разрешённых расширений теперь включает формат .mp3. Это трансформирует MyBlog из текстового движка в полноценную мультимедийную платформу, позволяя автору интегрировать аудиоподкасты и голосовые заметки в структуру статей, сохраняя при этом общую асинхронность и скорость отдачи контента.
- Стойкость к сетевым задержкам: Благодаря расширенным серверным таймаутам, MyBlog успешно завершает операции записи на диск даже при медленном исходящем соединении у пользователя.
2.3 Трюки с вёрсткой (Jinja2 Filters)
Внедрён кастомный фильтр insert_zwsp:
templates.env.filters['insert_zwsp'] = insert_zero_width_spaces
Он автоматически вставляет невидимые пробелы в аномально длинные строки (более 20 символов), которые не являются HTML-тегами. Порог был увеличен с 10 до 20 символов в ходе оптимизации, чтобы исключить разрывы обычных русских слов и сохранить корректную работу алгоритмов ёфикации. Это спасает мобильную вёрстку от "разрывов" из-за сверхдлинных ссылок или технических строк, сохраняя при этом целостность естественного языка.
2.3.1 Типографика и ёфикация
Помимо технических манипуляций со строками, проект следует строгому стандарту ёфикации текста. Использование буквы «ё» во всех материалах блога – это не просто прихоть, а часть философии чистоты контента. Корректная обработка спецсимволов и принудительная ёфикация через фильтры Jinja2 делают чтение технических статей более эстетичным и грамотным, что выделяет проект на фоне типичных «быстрых» решений.
2.4 Интеллектуальный мост: Blog Master (Visual Engine)
В экосистему MyBlog интегрирован мощный визуальный конструктор, позволяющий создавать профессиональные обложки и карточки-анонсы в стиле Flexy без использования Photoshop.
- WYSIWYG-редактирование: Реализован полноценный визуальный редактор на базе
contenteditable. Автор может менять иерархию заголовков (H1, H2, P), настраивать выравнивание и добавлять акцентные блоки (Quotes, Callouts) прямо на лету. - Динамическая работа с медиа: Внедрена функция «умной» вставки изображений через Drag-and-Drop или буфер обмена (
Ctrl+V). Система позволяет интерактивно управлятьY-offset(смещением) картинки внутри карточки, добиваясь идеальной композиции. - Форматирование без лишнего кода: Внедрена система «тихой» очистки вставляемого текста. При вставке извне скрипт автоматически удаляет лишние HTML-теги, сохраняя только чистый текст, что гарантирует стабильность финальной вёрстки.
- Многоформатный экспорт (PNG / WebP): Благодаря библиотеке
html2canvasреализован рендеринг DOM-дерева в растровое изображение с масштабомscale: 2. Это обеспечивает высокую чёткость графики для Retina-дисплеев. Поддержка формата WebP позволяет получать обложки с минимальным весом при сохранении 90% качества. - Мультиформатная гибкость (Cross-Platform): Конструктор поддерживает мгновенное переключение между популярными форматами: от классического 16:9 (YouTube/Web) до 1:1 (Square) и портретного Insta 4:5. Система автоматически масштабирует рабочую область для комфортного редактирования на любых мониторах, сохраняя при этом Pixel Perfect точность при экспорте
[!WARNING] Исключительно для ПК
Конструктор является профессиональным инструментом и доступен только в десктопной версии. В мобильных браузерах доступ намеренно ограничен, так как корректная вёрстка и рендеринг шрифтов требуют строго определённой ширины экрана. Только на ПК рабочая область гарантирует режим Pixel Perfect: когда финальный файл в форматах PNG или WebP в точности соответствует тому, что вы видите на своём мониторе, без нежелательных переносов строк или искажений.
Благодаря интеллектуальному сбросу масштаба перед рендерингом, вы получаете кристально чистое изображение в исходном высоком разрешении, независимо от выбранного формата холста.
3. Обоснование стека
- FastAPI: Минималистичен, быстр, асинхронен. Позволяет легко расширять проект.
- Uvicorn: ASGI-сервер с расширенными правами доступа к системным ресурсам (
LimitNOFILE=65535). Это позволяет приложению бесперебойно обрабатывать сотни одновременных соединений и потоковую передачу видео, исключая ошибки «Too many open files» под высокой нагрузкой. - Markdown: Выбран как стандарт де-факто для написания заметок (идеальная совместимость с Obsidian).
- Jinja2: Серверный рендеринг исключает необходимость в сложных фронтенд-фреймворках, сохраняя при этом интерактивность.
4. Итоги и эксплуатация
- Производительность: Благодаря связке In-memory Indexing на бэкенде и Max-Visible Limit на фронтенде, скорость отклика интерфейса остаётся константной (одинаково быстрой) как при 10 статьях, так и при 5000.
- Безопасность: Эшелонированная оборона на фронтенде и бэкенде.
Архитектурный вывод: Это надёжное монолитное решение «всё в одном», которое превращает простой текстовый архив в современную высокотехнологичную платформу.
2. Клиентская часть: main.html (Главная страница)
2.1 UI/UX и дизайн-система
Дизайн выполнен в стиле Modern Dark Minimalism.
В свежей итерации интерфейс стал более симметричным и сфокусированным. Основные изменения коснулись визуальной иерархии:
- Центрированная композиция: Блок поиска (
#searchInput) и облако тегов теперь выровнены по центру, что создаёт более сбалансированный вид на десктопах. Поиск получил эффектbackdrop-filter: blur(10px), подчёркивающий глубину интерфейса. - Умные карточки статей: Каждая плитка списка теперь имеет увеличенный верхний отступ (
45px), чтобы освободить пространство под динамический бейдж категории. Плавный подъём карточки при наведении (translateY(-4px)) дополнен глубокой тенью, выделяющей активный контент. - Zero-runtime Icons: Иконка поста (
.post-icon) сохранила свою лёгкость, отрисовываясь на чистом CSS через псевдоэлементы, что гарантирует мгновенный рендеринг без внешних запросов. - Backend-фильтрация контента: В отличие от стандартных решений, где приватный контент просто помечается иконкой «замок», в MyBlog реализована стратегия полной невидимости. Если пользователь не авторизован, эндпоинт
/на уровне сервера исключает из выборки все файлы с префиксом[P]. Это предотвращает утечку метаданных и названий секретных статей, делая их существование для случайного посетителя абсолютно скрытым.
2.2 Динамическая генерация категорий (The Tag System)
Одной из ключевых фишек интерфейса является автоматическая трансформация структуры карточек при загрузке страницы. Система на лету считывает метаданные из названий файлов и модифицирует DOM-дерево для каждой статьи.
- Логика работы: Скрипт
initCategoriesанализирует атрибутdata-name. Если название файла начинается с квадратных скобок (например,[Soft] Прошивка.md), запускается алгоритм визуального разделения контента. - Модификация заголовков: Из видимой части названия статьи автоматически вырезается технический префикс в скобках. Это позволяет хранить файлы в структурированном виде, но отображать их максимально чисто и эстетично.
- Внедрение визуальных бейджей: В начало каждой карточки (
li) скрипт принудительно добавляет элемент.post-category. Это создаёт эффектный графический маркер в углу плитки, который визуально отделяет тематику от основного текста.
Техническая реализация:
const match = fullName.match(/^\[(.*?)\]/);
if (match) {
const catName = match[1];
categories.add(catName);
item.dataset.category = catName.toLowerCase();
// Создание и внедрение графического бейджа
const badge = document.createElement('div');
badge.className = 'post-category';
badge.textContent = catName;
// Очистка заголовка от технических скобок
const cleanTitle = fullName.replace(/^\[.*?\]\s*/, '');
linkSpan.textContent = cleanTitle;
item.prepend(badge);
}
Этот подход полностью избавляет от ручного прописывания тегов в базе данных. Система сама строит дерево категорий и формирует облако тегов в верхней части страницы (categoryBox) исключительно на базе реальных префиксов в именах файлов. Плавное переключение между разделами происходит мгновенно на стороне клиента, обеспечивая безупречный UX.
2.2.1 Система приоритетов (Sticky Posts)
В скрипт initCategories интегрирован алгоритм проверки символа !.
- Если имя файла начинается с восклицательного знака, карточка получает CSS-класс
.pinned. - Такие статьи визуально выделяются акцентной полосой слева и иконкой гвоздика 📌
- Логика очистки заголовка автоматически удаляет
!из видимого текста, оставляя название чистым. - Визуальная индикация закрепов: Помимо иконки гвоздика 📌, закреплённые статьи выделяются за счёт CSS-класса
.pinned. Мы добавили эффект акцентной полосы слева (черезbox-shadow: inset 5px 0 0 0 var(--accent)), что создаёт чёткий вертикальный маркер приоритета. Это позволяет пользователю мгновенно вычленять важный контент в общем потоке постов, не перегружая карточку лишними графическими элементами.
[!WARNING] Важно
Символ!должен стоять самым первым в названии файла (например,![Soft] Настройка.md), иначе скрипт не распознает его как команду для закрепления.
2.3 Динамическая фильтрация и поиск
Вместо того чтобы нагружать сервер запросами при каждом вводе буквы, поиск реализован на стороне клиента (Client-side Filtering).
- Поиск: Работает мгновенно через
includes()по атрибутамdata-name. - Категории: Переключаются без перезагрузки страницы. Пользователь видит результат сразу.
- Счётчик: Элемент
#articles-countдинамически обновляется, показывая количество найденных записей. Это отличный UX-паттерн. - Интеллектуальная подгрузка (Lazy Rendering): Для обеспечения стабильных 60 FPS при поиске внедрена система постепенного вывода контента. По умолчанию на экран выводится первая сотня совпадений, а доступ к остальному архиву осуществляется через кнопку «Показать ещё». Это исключает «фризы» браузера при работе с тысячами записей, сохраняя при этом полный доступ ко всей базе статей без перезагрузки страницы.
2.4 AJAX-управление (Админ-панель)
Для авторизованных пользователей предусмотрена возможность управления архивом.
- Safe Delete: Удаление статей происходит через
fetch()с подтверждениемconfirm(). После успешного удаления элемент исчезает из DOM без перезагрузки всей страницы (el.remove()), что субъективно делает интерфейс очень быстрым. - CSRF-защита (базовая): Использование заголовка
X-Requested-With: XMLHttpRequestпозволяет серверу отличать автоматизированные запросы от ручных переходов.
2.5 Технические особенности вёрстки
- CSS Grid: Список постов использует
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)). Это самая современная техника, которая автоматически распределяет карточки по ширине, не оставляя пустых мест. - Zero-runtime Iconography: Иконки постов (класс
.post-icon) отрисованы на чистом CSS (псевдоэлементы::beforeи::after). Это экономит лишние HTTP-запросы к SVG или шрифтовым иконкам и гарантирует мгновенную отрисовку. - GPU-ускорение и плавность: Для всех анимаций (ховеры карточек, появление элементов) используются CSS-трансформации, что задействует аппаратное ускорение видеокарты. Это критично для того, чтобы интерфейс не «лагал» на мобильных устройствах при большом количестве постов.
- Zero-Dependency Iconography:Проект полностью отказывается от внешних шрифтовых иконок. Все графические элементы (маркеры категорий, иконки постов) реализованы на чистом CSS. Это избавляет от лишних HTTP-запросов и ускоряет первую отрисовку страницы (LCP).
- Кастомная навигация по контенту: Для длинных списков файлов в менеджере внедрена авторская стилизация скроллбара (
-webkit-scrollbar). Она выполнена в акцентных цветах Flexy (--accent), что исключает появление стандартных «белых» полос прокрутки, выбивающихся из тёмной темы, и обеспечивает визуальную целостность интерфейса.
3. Обоснование архитектурных решений фронтенда
- No Framework (Vanilla JS): Использование чистого JavaScript \u2014 осознанный выбор. Для такого функционала React или Vue были бы избыточны (overkill), а текущий код весит всего пару килобайт и работает быстрее любого фреймворка.
- Jinja2 Hydration: Начальный список статей рендерится сервером, а затем "подхватывается" скриптами для фильтрации. Это сохраняет SEO-показатели (поисковики видят все ссылки) при полной интерактивности.
- LocalStorage Bypass: В отличие от предыдущих модулей, здесь данные полностью контролируются сервером, а фронтенд лишь управляет их отображением.
Плюсы:
- Мгновенная реакция на действия пользователя.
- Идеальное отображение на мобильных устройствах.
- Отсутствие "тяжёлого" JS-бандла.
Минусы:
- При очень большом списке статей (более 1000) клиентский поиск может потреблять больше ресурсов CPU, чем серверный. Но для личного блога это недостижимый предел.
Полный разбор архитектуры MyBlog: Article View Engine
Этот модуль (article.html) отвечает за рендеринг и интеллектуальное обогащение контента. Основная фишка заключается в Post-processing на стороне клиента. Мы не просто выводим HTML, мы его дорабатываем авторскими скриптами для достижения безупречного UX и полной автономности.
1. Клиентская обработка контента (Smart Post-processing)
1.1 Оживление текстовых ссылок
Стандартный парсер Markdown часто игнорирует простые текстовые URL, не превращая их в кликабельные элементы. Наш скрипт автоматизирует этот процесс: он находит все строки в тексте соответствующие паттерну https://, и оборачивает их в активные HTML-ссылки. Это гарантирует корректную навигацию, даже если автор статьи забыл использовать синтаксис разметки.
const urlRegex = /(?<!["=])(https?:\/\/[^\s<]+)/g;
articleBody.querySelectorAll('p, li, td').forEach(el => {
el.innerHTML = el.innerHTML.replace(urlRegex, (url) => {
return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
});
});
Инженерная деталь: Используется регулярное выражение с Lookbehind (?<!["=]). Это критически важный предохранитель: он не даёт скрипту испортить уже существующие HTML-теги, где URL находится внутри атрибутов src или href.
1.2 Динамический парсинг заголовка (Title Engine)
Здесь применяется логика автоматических визуальных меток. Если заголовок статьи в Markdown-файле имеет вид ![OS] Настройка Windows, скрипт выполняет три задачи:
- Обработка закрепов: Находит символ
!в начале строки и помечает статью как приоритетную, добавляя иконку гвоздика \u1f4cc. - Выделение категорий: Извлекает тег
[OS]и преобразует его в эффектный отдельный графический элемент (category-label) над основным названием. - Очистка заголовка: Полностью удаляет технические префиксы (
!и[]) из текста<h1>.
В актуальной версии движка обработка H1 была вынесена из общего цикла JavaScript-обработки текстовых блоков. Теперь за его отображение отвечают строгие CSS-правила с приоритетом!important. Это гарантирует режим Pixel Perfect: заголовок всегда остаётся видимым, не "схлопывается" и корректно переносится по словам даже при наличии сложных символов (например, длинного тире), что исключает любые конфликты со скриптами пост-процессинга
Такой подход позволяет сохранять профессиональную структуру статьи на сайте, оставляя при этом исходные файлы на диске удобными для поиска и чёткой сортировки в редакторе (например, в Obsidian).
[!WARNING] Важно
Порядок символов в названии файла критичен: первым должен идти восклицательный знак, затем категория в скобках, и только потом название. Пример:![Soft] Твикер.md.
1.3 Система умных спойлеров (Media Spoiler Engine)
- Реализован обработчик атрибута
data-spoiler="true". Если скрипт находит этот атрибут у тегов<img>или<video>, он динамически оборачивает медиа в контейнер.article-spoiler. - Визуальная защита: На контент накладывается блюр 40px и выводится предупреждающая плашка «NSFW / 18+».
- Интерактивность: Контент открывается только после осознанного клика пользователя. При повторном клике блюр возвращается, что обеспечивает приватность просмотра.
2. Работа с кодом и таблицами
2.1 Code Blocks & Copy Engine
Любой блок программного кода автоматически оборачивается в контейнер .code-block, куда динамически инжектируется кнопка копирования.
- UX-фишка: При клике иконка копирования меняется на галочку (чек-марк) и подсвечивается акцентным цветом на 2 секунды. Это реализует паттерн «мгновенного фидбека», давая пользователю чётко понять: код уже в буфере обмена.
- Шрифты: Для кода жёстко прописаны модульные моноширинные шрифты (
Consolas,Monaco), что критично для профессионального восприятия технических статей.
2.2 Адаптивные таблицы (Responsive Data Tables)**
Таблицы в вебе – это один из самых «капризных» элементов. Если их просто оставить как есть, они напрочь ломают мобильную вёрстку, растягивая страницу по горизонтали так, что пользователю приходится скроллить весь сайт влево-вправо. В MyBlog реализовано изящное гибридное решение:
1. Серверный этап (Генерация)
Расширение tables в библиотеке markdown превращает стандартную Markdown-разметку:
| Заголовок 1 | Заголовок 2 |
|-------------|-------------|
| Текст 1 | Текст 2 |
в чистый HTML-код: теги <table>, <thead>, <tbody>, <tr> (строки) и <td> (ячейки). Сами по себе эти теги не умеют подстраиваться под размер экрана.
2. Фронтенд-этап (Адаптация)
Поскольку таблицы «дубовые» по своей природе, в твоём коде (в модуле article.html) используется специальный JS-скрипт.
Что он делает (алгоритм):
- Находит все таблицы, сгенерированные сервером.
- Проверяет их ширину и, вместо того чтобы дать им «разорвать» дизайн, оборачивает каждую таблицу в контейнер
div.table-wrapperсо свойствомoverflow-x: auto.
Как это выглядит для пользователя:
Вместо того чтобы вся страница начала «болтаться» на экране смартфона, сама статья остаётся стабильной, а внутри неё появляется область с таблицей, которую можно плавно скроллить пальцем. Это классический пример того, как минималистичный бэкенд дополняется умным фронтендом для обеспечения безупречного UX.
- Markdown
tablesотвечает за структуру и данные. - Vanilla JS отвечает за то, чтобы эти данные не превратили чтение статьи на телефоне в кошмар.
3. Дизайн и типографика статьи (Article View Engine)
Модуль рендеринга контента следует философии Modern Dark Minimalism, обеспечивая безупречный UX при чтении сложных технических материалов:
- Оптимизация когнитивной нагрузки: Ширина текстового блока ограничена
720px(класс.content). Это создаёт идеальную длину строки, минимизирующую усталость глаз при длительном чтении. - Динамическая адаптивность: Заголовки используют функцию
clamp(26px, 7vw, 42px), что позволяет им органично масштабироваться между огромными 4K-мониторами и экранами компактных смартфонов. - Иерархическая навигация:
- H2 выделены массивным акцентным бордером (
5px solid var(--btn-blue)), выступая в роли визуальных якорей. - H4 дополнены нижним разделением, подчёркивающим структуру подразделов.
- Бейджи категорий автоматически инжектируются в шапку статьи, визуально отделяя тематику (напр. [Soft]) от основного названия.
- H2 выделены массивным акцентным бордером (
- Типографика и оптическая стабилизация: Использование шрифта Tahoma с межстрочным интервалом
1.75и размером параграфов1.15remобеспечивает эталонную читаемость. Чтобы текст не «резал» глаза на идеально чёрном фоне (особенно в браузерах без сглаживания), выбрано мягкое цветовое решение#b0bccd. Это минимизирует нагрузку на зрение при длительном изучении документации. - Мобильная пересборка (Mobile Breakpoints): При достижении ширины в
650pxинтерфейс переходит в мобильный режим:- Навигация трансформируется в горизонтальную ленту с инерционным скроллом.
- Кнопки управления (Экспорт/Поделиться) растягиваются на всю ширину для удобства нажатия пальцем.
- Блоки сравнения изображений (
.compare-wrapper) перестраиваются из горизонтального ряда в вертикальный стек. - Размер шрифта в параграфах снижается до
1.05remдля сохранения информационной плотности. - Навигационный стаб (BackToTop): Для удобства работы с лонгридами внедрена умная кнопка быстрого возврата к шапке статьи. Она появляется автоматически при прокрутке страницы вниз более чем на
400px. Кнопка реализована с использованиемbackdrop-filter: blur(5px), что позволяет ей оставаться заметной на любом фоне, не перекрывая при этом контент и сохраняя общую эстетику тёмной темы.
Визуальная иерархия дополнена умными списками: маркеры ul/ol теперь имеют тот же мягкий оттенок #b0bccd, что и основной текст, и вынесены за пределы текстового блока (list-style-position: outside). Это сохраняет строгий ритм чтения и предотвращает визуальное "слипание" перечислений с основным контентом
[!WARNING] Важно
Использование фильтра размытия (blur) на кнопке не только выглядит эффектно, но и решает проблему читаемости текста, который оказывается «под» кнопкой во время скролла.
Технический акцент: Весь визуал реализован на чистом CSS без внешних шрифтовых иконок или тяжёлых UI-китов, что гарантирует мгновенную отрисовку страницы (LCP) даже на слабых устройствах.
3.1 Интеллектуальное оглавление (Smart TOC)
- Автоматическая структуризация (Dynamic TOC): Модуль
Article View Engineсамостоятельно анализирует структуру документа. Если количество заголовковH2иH3превышает три, скрипт динамически инжектирует блок «Содержание» в начало статьи. - Алгоритм иерархии: Подзаголовки
H3визуально вложены в родительские разделы с пониженной яркостью, создавая чёткую логическую карту материала. - Мобильная оптимизация: Для предотвращения чрезмерного растягивания страницы на смартфонах, межстрочный интервал в оглавлении принудительно снижен до
1.3, обеспечивая высокую плотность навигационных ссылок. - Иерархия заголовков: Скрипт не просто находит заголовки, он визуально разделяет их: подзаголовки
H3отображаются с отступом и пониженной яркостью, создавая чёткую логическую карту материала.
4. Интеграция с нативной системой (Share API)
Этот модуль отвечает за бесшовную передачу данных между веб-приложением и операционной системой пользователя.
4.1 Смарт-нормализация URL
Кнопка Поделиться не просто копирует URL, она выполняет глубокую очистку и интеллектуальное экранирование адреса:
// Декодируем текущий URL, чтобы работать с чистой кириллицей
let currentUrl = decodeURI(window.location.href);
// Принудительно кодируем спецсимволы, критичные для парсеров:
const beautyUrl = currentUrl
.replace(/!/g, '%21')
.replace(/\[/g, '%5B')
.replace(/\]/g, '%5D')
.replace(/ /g, '%20')
.replace(/P/g, '%50');
Инженерная деталь: Использование decodeURI позволяет получить «чистую» кириллицу, а ручное переопределение кодирования для символов !, [, ], P и пробелов гарантирует, что системные маркеры блога не будут «съедены» парсерами мессенджеров. Это делает ссылку полностью безопасной для передачи в Telegram, Discord или WhatsApp, сохраняя её валидность и аккуратный внешний вид.
4.2 Portable Article Engine (Экспорт)
Вместо стандартной печати в проект интегрирован механизм сборки автономного HTML-пакета. При нажатии на кнопку «Экспорт» происходит не просто копирование текущего DOM-дерева, а его интеллектуальная «санация»:
- Бинарная инъекция и прогресс: Скрипт асинхронно конвертирует все изображения, аудио и видео в формат Base64. Процесс сопровождается динамическим прогресс-баром (Сборка: X%), что обеспечивает визуальный отклик при работе с объёмными медиа-массивами.
- Интеллектуальная нормализация медиа: В процессе сборки пакета система автоматически декодирует URL-пути, извлекает оригинальные имена файлов (включая кириллицу) и внедряет их в атрибуты title и download. Это подготавливает автономный файл к корректному распознаванию системными загрузчиками ОС.
- Атомарная очистка DOM: Перед генерацией финального Blob-объекта скрипт проводит «санацию» дерева: удаляет интерактивное оглавление (TOC), скрывает служебные кнопки и возвращает блокам кода их первозданный вид (pre), избавляя оффлайн-копию от лишнего «мусора».
- Восстановление кода: Тегам pre возвращается их первозданный вид, без внедрённых скриптами статус-баров. Это гарантирует, что экспортированная статья будет содержать безупречный, валидный код, максимально приближённый к исходному Markdown-оригиналу.
- Сохранение приватности при экспорте: Система спойлеров полностью переносима. При экспорте статьи в автономный HTML-файл все атрибуты data-spoiler и соответствующие CSS-правила сохраняются. Это гарантирует, что даже в оффлайн-копии статьи «горячий» контент останется скрытым до осознанного клика пользователя, сохраняя приватность просмотра вне зависимости от наличия связи с сервером.
Результат: Пользователь получает один .html файл, который открывается в любом браузере без интернета и внешних зависимостей. Это превращает блог в инструмент создания переносимой документации, которую можно хранить вечно.
Цифровая сохранность типографики: Важной особенностью экспорта является полная консервация визуального стиля. Автономная копия статьи сохраняет абсолютную верность типографике: все результаты работы серверных фильтров, включая принудительную ёфикацию и невидимые пробелы (ZWSP), бережно переносятся в HTML-пакет. Это гарантирует, что даже через десятилетия оффлайн-копия будет выглядеть именно так, как её задумал автор, без «разрывов» вёрстки на новых устройствах.
4.3 Нативный Медиа-интерфейс
Для сохранения единого визуального кода и высокого быстродействия проект отказывается от тяжёлых кастомных плееров в пользу нативных элементов браузера. Чтобы стандартные компоненты ОС (на Windows, Android или iOS) не выбивались из общего стиля, применена адаптация через CSS-фильтры:
/* Инверсия цветов с коррекцией тона под тёмную тему */
audio { filter: invert(90%) hue-rotate(180deg) brightness(1.1); }
Это решение позволяет системным контроллерам выглядеть как органичная часть дизайна Modern Dark Minimalism, сохраняя при этом аппаратную оптимизацию и нативное управление громкостью.
Нативная поддержка именования: Использование атрибута download в связке с Base64-данными позволяет современным браузерам (включая Chrome) идентифицировать контент, предлагая пользователю человекочитаемые имена файлов при попытке сохранения медиа из автономной статьи.
Структурированные плейлисты: Для группировки аудиоматериалов реализована поддержка компактных плейлистов на базе связки <figure> и <figcaption>. Подписи к трекам наследуют общую типографику параграфов, превращая набор плееров в упорядоченную библиотеку. Такой подход гарантирует безупречную работу медиа-контента даже на старых устройствах, где кастомные JS-плееры могли бы вызвать задержки в отрисовке (LCP).
5. Безопасность и управление
- Safe Delete: Кнопка удаления доступна только владельцу (
is_auth) и защищена двойным барьером: проверкой на сервере иconfirmна фронте. - Noopener/Noreferrer: Все внешние ссылки, созданные скриптом, получают эти атрибуты. Это защищает от атак типа
tabnabbingи не передает данные о твоем блоге сторонним ресурсам.
Вердикт по модулю Article
Этот шаблон превращает простой текстовый файл в полноценную веб-страницу.
Главный плюс: Весь функционал (копирование кода, бейджи, ссылки) работает автономно и мгновенно.
Минус: Если в статье будет 500 блоков кода, инициализация 500 кнопок копирования может занять доли микросекунды (что на самом деле незаметно, но мы же задроты, верно?).
Полный разбор архитектуры MyBlog: Gallery & Masonry Engine
Галерея предназначена для отображения нейросетевых артов и видео. Основная техническая сложность здесь – работа с контентом разной высоты без создания визуальных дыр в сетке.
1. Masonry Grid: Математика вёрстки
Вместо использования тяжёлых библиотек (типа Isotope или Masonry.js), в проект интегрирован самописный легковесный алгоритм на Vanilla JS.
- Динамическое распределение: Система определяет количество колонок исходя из ширины экрана (от 1 до 3). Используется массив
colHeights, инициализированный нулями. - Алгоритм кратчайшей колонки: Для каждого элемента вычисляется его позиция: он всегда встаёт в ту колонку, которая в данный момент является самой кратчайшей. Это исключает появление пустых зон (дыр) при разной высоте контента.
- GPU-acceleration: Для перемещения карточек используется
translate3dвместо измененияtop/left. Это задействует аппаратное ускорение видеокарты, обеспечивая плавность 60 FPS при перестроении сетки. - Адаптивная деградация: На экранах менее 700px алгоритм Masonry автоматически отключается (
position: relative), переходя в режим классического вертикального потока. Это экономит ресурсы CPU на слабых смартфонах. - Математическая реализация:
const minH = Math.min(...colHeights), idx = colHeights.indexOf(minH);
item.style.transform = `translate3d(${idx * (itemWidth + gap)}px, ${minH}px, 0)`;
Страховка рендеринга:
Поскольку высота карточки неизвестна до загрузки медиа, вызов resizeInstance дублируется трижды: по событию load, через setTimeout(500) и отдельно по событию onloadedmetadata для каждого видео. Это гарантирует, что сетка не «поплывёт» после того, как тяжёлое видео подгрузит свои размеры.
Динамический расчёт контейнера:
В конце расчёта скрипт находит максимальное значение в colHeights и задаёт высоту родителю: gallery.style.height = Math.max(...colHeights) + "px". Без этого шага последующие элементы страницы (например, футер) «наехали» бы на галерею из-за абсолютного позиционирования элементов.
2. Работа с медиа-контентом
2.1 Поддержка видео
Галерея нативно поддерживает формат MP4. Для экономии ресурсов и создания "живого" эффекта превью:
- Видео воспроизводятся автоматически (
autoplay), без звука (muted) и по кругу (loop). - Атрибут
playsinlineгарантирует, что видео не будет разворачиваться на весь экран при старте на iPhone. - атрибут
webkit-playsinlineдля поддержки совсем старых версий iOS, если ты хочешь идеальной совместимости.
Технический нюанс мобильного воспроизведения: В скрипт рендеринга видео автоматически внедрён атрибутplaysinline. Это критически важная деталь для пользователей iOS: без этого параметра браузер Safari на iPhone принудительно разворачивает любое видео в системный полноэкранный плеер при старте. Сplaysinlineвидео остаётся внутри карточки галереи, сохраняя целостность интерфейса и Masonry-сетки.»
2.2 Умный Лайтбокс (Просмотрщик)
Реализована собственная система полноэкранного предпросмотра. При клике на медиаконтент создаётся оверлей с динамическим размытием заднего плана (backdrop-filter: blur(15px)). Это программно изолирует внимание пользователя на выбранном арте или видео, создавая глубокое погружение и превращая просмотр в полноценный визуальный опыт. Контент внутри лайтбокса адаптивен и ограничен по высоте (92vh), что исключает появление паразитных полос прокрутки и гарантирует корректное отображение на любых типах дисплеев.
Интеллектуальный рендеринг в модальном окне: Скрипт лайтбокса использует прямые ссылки на рабочие медиа-ресурсы и принудительно сбрасывает CSS-фильтры через content.style.filter = "none". Это гарантирует мгновенное отображение чёткого контента, даже если превью в сетке было сильно заблюрено
2.3 Система умных спойлеров (NSFW Spoiler Engine)
В логику рендеринга медиа-карточек интегрирован алгоритм автоматической защиты контента:
- Автоматический блюр в Masonry: Сетка Галереи обучена мгновенно распознавать файлы с суффиксом _S в имени (например, art_S.jpg). Такие карточки по умолчанию рендерятся с экстремальным размытием (blur 40px) и снабжаются сервисным бейджем «18+». Это позволяет безопасно смешивать любой контент в одной ленте, сохраняя эстетику и приличие интерфейса.
- Интерактивная интрига и Лайтбокс: При наведении курсора на заблюренную плитку эффект размытия мягко снижается до 25px, создавая визуальный отклик. Полное «раскрытие» контента происходит исключительно в полноэкранном лайтбоксе: JS-движок подхватывает чистый источник (src) и программно нейтрализует все фильтры цензуры, демонстрируя оригинал в идеальном качестве.
- Бесшовный визуальный код: Использование CSS-фильтров вместо замены исходников позволяет сохранить целостность Masonry-сетки и избежать «прыжков» вёрстки при взаимодействии с контентом. Это гарантирует стабильность позиций элементов даже при экстремальных значениях размытия.
3. Интеграция с данными ИИ (Prompt Management)
Каждая карточка в галерее – это контейнер для метаданных.
- Prompt Area: Текстовое поле с промтом по умолчанию скрыто и использует моноширинный шрифт
Consolasдля удобного чтения параметров генерации. - AJAX-сохранение: Для админа реализована возможность редактировать промты прямо "на лету" через
FormDataи эндпоинт/gallery/prompt_save. - Copy Engine: Быстрый механизм копирования промта для тех, кто хочет повторить генерацию.
4. Дизайн и UX-фишки
- Masonry Grid: Самописный алгоритм на чистом JS с GPU-ускорением (
translate3d). - Article Engine: Клиентская обработка ссылок (Lookbehind RegEx), кнопок копирования кода с мгновенным фидбеком и адаптивных таблиц через
table-wrapper. - Экспорт: Сборка автономного HTML-пакета с конвертацией медиа в Base64.
- Медиа-интерфейс: Адаптация системных элементов браузера под тёмную тему через инверсию фильтров.
5. Плюсы и минусы решения
Плюсы:
- Zero Library: Отсутствие внешних JS-зависимостей делает страницу экстремально лёгкой.
- GPU acceleration: Плавная перестройка сетки при изменении размера окна браузера.
- Flexibility: Галерея одинаково хорошо работает как с горизонтальными, так и с вертикальными артами.
Минусы:
- Initial Load: Функция
resizeInstanceдолжна ждать полной загрузки изображений, чтобы узнать их высоту (window.onload). На очень медленном интернете сетка может "прыгнуть" во время инициализации. Решается введением фиксированных пропорций для картинок (aspect-ratio), если они известны заранее.
Полный разбор MyBlog: Система доступа и управления контентом
1. Модуль авторизации: login.html
Страница входа выполнена в стиле Cyber-Dark. Здесь нет ничего лишнего, только функционал, защищённый логикой сессий.
1.1 Механизм редиректов (The "Next" Pattern)
Одной из ключевых особенностей является использование переменной next_url.
- Логика: Если ты пытаешься зайти в галерею будучи неавторизованным, сервер перекидывает тебя на
/login?next=gallery. После ввода пароля страница не просто выкинет тебя на главную, а вернёт именно в галерею. - Инженерная реализация: Значение передаётся через скрытое поле формы (
<input type="hidden">), обеспечивая бесшовный пользовательский опыт (UX).
1.2 Фронтенд-валидация
- Zoom Prevention: Для
inputустановленfont-size: 16px. Это маленькая, но важная деталь для iOS-устройств – при меньшем размере шрифта браузер Safari принудительно увеличивает масштаб страницы при фокусе на поле, что ломает вёрстку. Здесь это исправлено.
2. Модули управления контентом (Data Ingestion)
Это высокотехнологичные интерфейсы для взаимодействия с файловой системой сервера через абстракцию FastAPI UploadFile. Основная архитектурная особенность – полная асинхронность и клиентская валидация перед отправкой.
2.1 Универсальный медиа-загрузчик (upload_media)
В отличие от классических галерей, этот модуль спроектирован как гибкий файловый менеджер для медиафайлов.
- Динамическая адресация: Пользователь может выбрать целевую папку в static/ (например, для иконок проектов или звуковых эффектов) прямо в интерфейсе загрузки. Система автоматически создаст дерево директорий, если оно отсутствует.
- Drag-and-Drop и пакетная обработка: Поддерживается одновременная загрузка до 50 файлов с визуальной индикацией прогресса через XHR-события.
- Умное превью пути: Скрипт на лету формирует итоговую ссылку на файл (/static/path/file.ext), что позволяет автору мгновенно копировать путь для вставки в Markdown-черновик.
2.1.1 Процессор статей (upload_article)
- Валидация расширений: Сервер принимает исключительно файлы .md. При попытке загрузки сторонних форматов система мгновенно отсекает запрос до начала записи на диск, обеспечивая безопасность хранилища.
- Автоматизация публикации: После успешной передачи данных система выполняет «мягкий» редирект на главную страницу через 1.5 секунды. Этого времени достаточно для визуального подтверждения статуса «Опубликовано», после чего пользователь сразу видит обновлЁнный список постов.
- Санитарная обработка заголовков: Модуль загрузки оснащён логикой предотвращения дублирования технических символов. Если пользователь вручную добавил ! в название файла и одновременно активировал чекбокс «Закрепить» в интерфейсе, скрипт автоматически очистит имя от лишних знаков и сформирует корректный заголовок. Это исключает появление артефактов вроде !![Soft] и гарантирует стабильную работу парсера категорий.
2.2 Логика очистки имен (Sanitization)
На странице загрузки статей реализована важная проверка:
safe_name = re.sub(r'[^\w\s\-\.\[\]\(\),!«»"\'\u00A0—;?]', '', file.filename).strip()
Это защищает сервер от инъекций в именах файлов. Если файл называется [AI]; rm -rf /; .md, он превратится в безобидный [AI] rm -rf .md.
3. Административные операции (Destructive Actions)
Проект включает в себя функции «ядерного уничтожения» данных для моментальной и безвозвратной очистки всего архива.
delete_all: Эти эндпоинты защищены двойным барьером.- Кнопка на фронте вызывает
confirm(). - Декоратор
require_authна бэкенде проверяет наличие активной сессии. - Асинхронное удаление: При удалении одной статьи используется
fetch, чтобы не обновлять страницу – это современный стандарт (SPA-подобное поведение).
Полный разбор архитектуры MyBlog: Data Ingestion (Загрузка данных)
Этот раздел посвящён страницам upload_gallery.html и upload_article.html. С точки зрения архитектуры – это порты ввода данных, реализующие паттерн Client-side File Processing перед отправкой на FastAPI.
1. Стек и UX-инженерия
Обе страницы используют единый визуальный код, но разные механизмы валидации в зависимости от типа контента.
1.1 Универсальный Drag-and-Drop
Вместо стандартных и скучных кнопок выбора файлов реализована интерактивная зона – dropzone.
- Механика: Использование событий
ondragover,ondragleaveиondrop. При наведении область подсвечивается (scale(1.02)и смена цвета рамки), обеспечивая визуальный отклик (Affordance). - Пакетный режим: Атрибут
multipleвinput type="file"позволяет за один проход загрузить весь архив статей или пачку сгенерированных артов.
1.2 Асинхронные пайплайны загрузки
Для отправки данных используется асинхронный fetch с объектом FormData.
Инженерный профит: Страница не перезагружается в процессе отправки. Пользователь видит статус ("Загрузка на сервер...", "Успешно!") в реальном времени.
2. Глубокий разбор: Загрузка в Галерею (upload_gallery)
Этот модуль сложнее, так как он работает с бинарными данными (изображения и видео).
2.1 Двойная валидация
Перед отправкой фронтенд выполняет первичную проверку:
- По MIME-типу:
['image/jpeg', 'image/png', 'image/gif', 'video/mp4'].includes(file.type). - По расширению: На случай, если браузер некорректно определил тип файла.
Это экономит трафик: если пользователь случайно выберет .zip архив, он получит ошибку мгновенно, без ожидания ответа от сервера.### 2.2 Обработка результатов
После загрузки сервер возвращает JSON со списком результатов. Скрипт анализирует его:
const successCount = data.results.filter(r => r.status === 'ok').length;
Это позволяет реализовать частичный успех: если из 10 файлов 8 загрузились, а 2 были повреждены, пользователь узнает точное количество.
3. Глубокий разбор: Загрузка Статей (upload_article)
Этот модуль адаптирован под текстовый Workflow (Obsidian/Notepad++).
3.1 Фильтрация формата .md
В отличие от галереи, здесь кнопка "Опубликовать" (#uploadBtn) изначально заблокирована (disabled). Она "оживает" только тогда, когда в массив selectedFiles попадают файлы с расширением .md.
selectedFiles = Array.from(files).filter(f => f.name.toLowerCase().endsWith('.md'));
3.2 Автоматизация редиректа
После успешной публикации статьи пользователь автоматически перенаправляется на главную страницу блога через 1.5 секунды. Этого времени достаточно, чтобы увидеть сообщение об успехе, после чего система сразу показывает обновлённый список постов.
4. Обоснование инфраструктурных решений
- No Heavy Dependencies: Весь функционал drag-and-drop написан на чистом JS без библиотек типа Dropzone.js. Это гарантирует отсутствие конфликтов и минимальный размер страницы (~3-5 Кб).
- Security by Design:
- На фронтенде ограничены типы файлов (
accept=".md",accept="image/*"). - На бэкенде (как мы помним из разбора
main.py) стоит повторная проверка. Это классическая стратегия Defense in Depth (эшелонированная оборона). - Mobile-First: На мобильных устройствах зона
dropzoneадаптируется по высоте, а кнопки выбора файлов становятся крупнее, чтобы по ним было легко попасть пальцем.
5. Плюсы и минусы загрузчиков
Плюсы:
- Высокая скорость работы за счёт асинхронности.
- Прозрачная индикация процесса (пульсирующая анимация текста).
- Поддержка современных форматов и пакетной загрузки.
Минусы:
- Отсутствие визуальных превью (thumbnails) перед загрузкой в галерею. Это сознательное упрощение в пользу легкости кода, так как обычно пользователь знает, что именно он загружает.
Модули загрузки превращают статичное хранилище в динамическую платформу. Использование fetch и FormData делает процесс публикации контента почти мгновенным, превращая MyBlog в полноценную CMS (Content Management System) для личного использования.
Полный разбор архитектуры MyBlog: Authentication Gate
Здесь реализован классический паттерн Stateful Auth, где сервер контролирует доступ на основе сессионных кук, а фронтенд обеспечивает удобную точку входа.
1. UX-инженерия и "Mobile First"
Как и во всём проекте, здесь соблюдён строгий стандарт адаптивности.
- Инпут-хак для iOS: Для всех полей ввода установлен
font-size: 16px. Это решение исключает паразитное масштабирование (авто-зум) в браузере Safari на iPhone, которое обычно портит вёрстку при фокусе на текстовом поле. - Интерактивные состояния: Поля ввода (
input) подсвечиваются мягким синим свечением (box-shadow), а кнопка входа реагирует на ховер подъёмом по оси Y. Это даёт ощущение "упругости" интерфейса.
2. Логика перенаправлений (Next-параметр)Особое внимание уделено сохранению пути пользователя:
<input type="hidden" name="next_url" value="{{ next_url }}">
Техническая ценность: Если вы, будучи неавторизованным, попытаетесь зайти в панель загрузки статьи, система перекинет вас на логин, но запомнит ваш изначальный запрос. После успешного входа FastAPI прочитает это скрытое поле и вернёт вас именно туда, куда вы шли. Это избавляет от лишних кликов и навигации по меню заново.
- Автозаполнение: Использование атрибутов autocomplete="username" и autocomplete="current-password" помогает менеджерам паролей (Bitwarden, Google Passwords) корректно распознавать поля. Для стабильной работы на мобильных устройствах рекомендуется всегда связывать label и input через атрибут id.
-
Индикация ошибок: Блок .error отображается сервером (Jinja2) только при неудачной аутентификации. Он оформлен цветом #ef4444 (стандарт Soft Red) и имеет полупрозрачный фон для удобства чтения в тёмной теме.
## 4. Дизайн-код -
Визуальная изоляция: Карточка логина (
.login-container) имеет чёткую границу и тень, что отделяет форму от общего фона и фокусирует внимание пользователя на действии. - Транзишны: Плавность переходов (
var(--transition)) во всём проекте делает интерфейс отзывчивым и современным.
Общий итог по проекту (The Big Picture)
Мы разобрали MyBlog сверху донизу:
- Ядро (FastAPI): Асинхронная мощь и работа с плоскими файлами (Markdown/JSON) вместо тяжёлых БД.
- Фронтенд (Vanilla JS + Jinja2): Молниеносная скорость работы, отсутствие лишних зависимостей и библиотек.
- Галерея (Masonry Engine): Умная сетка на GPU-ускоренных трансформациях.
- Статьи (Markdown Engine): Автоматическая конвертация заметок из Obsidian в живые статьи с копированием кода и адаптивными таблицами.
- Админка (Data Ingestion): Удобная загрузка файлов через Drag-and-Drop и безопасная авторизация.